#pragma once
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>

#include "Connection.hpp"
#include "Epoller.hpp"

// 暂时叫做TcpServer->rename
// Reactor一个类似connection的容器，核心工作就是
// 1. 管理connection和对应的内核事件
// 2. 事件派发，调用处理
class Reactor
{
    static const int gnum = 64;

public:
    Reactor() : _epoller(std::make_unique<Epoller>()), _isrunning(false)
    {
    }
    void AddConnection(int fd, uint32_t events, const InetAddr &addr, int type)
    {
        // 1. 构建一个connection
        Connection *conn = new Connection(fd);
        conn->SetEvents(events);
        conn->SetConnectionType(type);
        conn->SetAddr(addr);
        conn->SetReactor(this); // 将当前对象设置进入所有的conn对象中，让所有连接对象都能接收到就绪事件的派发

        // 设置对connection的上层处理，即，如果该connection就绪被激活，我们应该如何处理它？
        if (conn->Type() == ListenConnection)
        {
            conn->RegisterHandler(_OnConnect, nullptr, nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver, _OnSender, _OnExcepter);
        }

        // 2. fd和events写透到内核中，托管给epoll
        if (!_epoller->AddEvent(conn->Sockfd(), conn->Events()))
            return;

        // 3. 托管给_connections
        _connections.insert(std::make_pair(fd, conn));
    }
    //关心读/写连接
    void EnableConnectionReadWrite(int sockfd, bool readable, bool writeable)
    {
        if (!IsConnectionExists(sockfd))
        {
            return;
        }

        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _connections[sockfd]->SetEvents(events);//设置sockfd对应的events

        // 写透到内核中！
        _epoller->ModEvent(_connections[sockfd]->Sockfd(), _connections[sockfd]->Events());//修改Sockfd对应的Events
    }
    void DelConnection(int sockfd)
    {
        // 0. 安全检测
        if (!IsConnectionExists(sockfd))
        {
            return;
        }
        LOG(INFO, "sockfd %d quit, 服务器释放所有资源\n", sockfd);
        // 1. 在内核中移除对sockfd的关心
        EnableConnectionReadWrite(sockfd, false, false);
        _epoller->DelEvent(sockfd);
        // 2. sockfd 关闭
        _connections[sockfd]->Close();
        // 3. 在Reactor中移除对Connection的关心
        delete _connections[sockfd];
        _connections.erase(sockfd);
    }
    void LoopOnce(int timeout)
    {
        int n = _epoller->Wait(revs, gnum, timeout);
        for (int i = 0; i < n; i++)
        {
            int sockfd = revs[i].data.fd;
            uint32_t revents = revs[i].events;

            // 把所有的错误异常（添加上读写就绪），延迟到读写时，再统一处理
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP) // 连接断开了
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)//先读
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->_handler_recver)
                    _connections[sockfd]->_handler_recver(_connections[sockfd]); // 读事件就绪，派发给对应的conn
            }
            if (revents & EPOLLOUT)//后写/响应
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->_handler_sender)//先检测Connection是否存在，防止前面出现异常connection删除了，现在又访问导致出错
                    _connections[sockfd]->_handler_sender(_connections[sockfd]); // 写事件就绪，派发给对应的conn
            }
        }
    }
    void Dispatcher() // 事件派发
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            LoopOnce(timeout); // 默认阻塞等待的. //LoopOnce一次返回，提醒就绪
            // 做做其他事情
            // 就可以获取新的fd,并添加了！
            PrintDebug();
        }
        _isrunning = false;
    }
    bool IsConnectionExists(int sockfd)//先检测Connection是否存在，防止前面出现异常connection删除了，现在又访问导致出错
    {
        return _connections.find(sockfd) != _connections.end();
    }
    void SetOnConnect(handler_t OnConnect)
    {
        _OnConnect = OnConnect;
    }
    void SetOnNormalHandler(handler_t recver, handler_t sender, handler_t excepter)
    {
        _OnRecver = recver;
        _OnSender = sender;
        _OnExcepter = excepter;
    }
    void PrintDebug()
    {
        std::string fdlist;
        for (auto &conn : _connections)
        {
            fdlist += std::to_string(conn.second->Sockfd()) + " ";
        }
        LOG(DEBUG, "epoll管理的fd列表: %s\n", fdlist.c_str());
    }
    ~Reactor()
    {
    }

private:
    // key: sockfd
    // value: Connetion*
    std::unordered_map<int, Connection *> _connections; // Event
    std::unique_ptr<Multiplex> _epoller;
    bool _isrunning;
    struct epoll_event revs[gnum];//用来捞取的数组

    // Reactor中添加处理socket的方法集合
    // 1. 处理新连接
    handler_t _OnConnect;//新连接处理
    // 2. 处理普通的sockfd，主要是IO处理
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;//异常处理
};